<?php
namespace app\wx_pay\controller;
use think\facade\Db;
use think\facade\Session;

class JsApiPayV3{
    /**
     * $type string 支付类型【小程序或h5】
     * $description string[1,127] 商品描述
     * $out_trade_no string[6,32] 订单号
     * $money any-number 金额
     * $openid 用户openid
     * $notify_url 回调地址
     * $timestamp string 时间戳
     * $uid 提交的submit_id
    **/
    //下单和发起支付
    public  function pay($type,$description,$out_trade_no,$money,$openid,string $timestamp,$uid,$notify_url=''){
        /////JSAPI下单//////
        //$notify_url =  'http://blqqun.yyuebd.com/v3_pay/hd';
        $appid = $type=='h5'?config('wx')['accountAppId']:config('wx')['appletAppId'];
        $param_data_arr = array(
            'mchid'        => config('wx')['mch_id'],
            'out_trade_no' => $out_trade_no,
            'appid'        => $appid,
            'description'  => $description,
            'notify_url'   => empty($notify_url)?$_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['HTTP_HOST'].'/wx_pay/js_api_pay_v3/pay_callback':$notify_url,
            'amount'       => [
                'total'    => intval( strval($money * 100) ),//0.01
                'currency' => 'CNY'
            ],
            'payer'=>[
                //'oBeVo5kE8BaMscKSonI4RV2Oc5jg'
                'openid'=>$openid
            ]
        );
        //删除反斜杠
        $body = stripslashes(json_encode($param_data_arr));
        $http_method = 'POST';
        $url = 'https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi';
        //$timestamp = time();//时间戳
        $nonce = rand_code();//随机串
        $header = $this->sign($timestamp,$nonce,$http_method,$url,$body);
        $data = $this->curl($http_method,$url,$body,$header,$timeout=5);
        //得到预支付id
        $prepay_id = $data['prepay_id'];

        /////JSAPI调起支付API//////
        $package = "prepay_id={$prepay_id}";
        $paySign= self::paySign($appid,$timestamp,$nonce,$package);
        //返回给前端的参数，调用 WeixinJSBridge.invoke 弹窗支付
        $pay_arr = [
            'appId'=>$appid,
            'timeStamp'=>$timestamp,
            'nonceStr'=>$nonce,
            'package'=>$package,
            'signType'=>'RSA',
            'paySign' =>$paySign
        ];
        Db::table('sign_order')->insert(['out_trade_no'=>$out_trade_no,'uid'=>$uid,'pay_price'=>$money,'add_time'=>date('Y-m-d H:i:s',$timestamp)]);
        return ['status'=>200,'pay_data'=>$pay_arr];
    }
    //支付成功，回调方法
    public function pay_callback(){
        //接收微信返回的参数
        $data = file_get_contents("php://input");
        //转为数组
        $notify_data =  json_decode($data,true);
        //截取 resource 数组值
        $resource =  $notify_data['resource'];
        $apiv3 = config('wx')['app_key3'];
        //解密AES///
        $AesUtil = new AesUtil($apiv3);
        $associatedData = $resource['associated_data'];
        $nonceStr = $resource['nonce'];
        $ciphertext = $resource['ciphertext'] ;
        if($AesUtil->decryptToString($associatedData, $nonceStr, $ciphertext)!=false){
            $ok_aes =json_decode($AesUtil->decryptToString($associatedData, $nonceStr, $ciphertext),true);
        }else{
            return json(['status'=>500,'msg'=>'解密失败']);
            die;
        }
        //取得订单号
        $out_trade_no = $ok_aes['out_trade_no'];
        //file_put_contents('/www/wwwroot/blqqun.yyuebd.com/app/controller/1.txt',$out_trade_no);
        $ok_update =  Db::table('sign_order')->where('out_trade_no',$out_trade_no)->update(['ispay'=>1,'pay_time'=>date("Y-m-d H:i:s")]);
        if($ok_update==1){
            return json_encode(['code'=>'SUCCESS','message'=>'数据处理完成！']);
        }else{
            return json_encode(['code'=>'FAIL','message'=>'逻辑处理失败！请重发！']);
        }

    }
    //GET 获取平台证书列表
    public function ok_cert(){
        $http_method = 'GET';
        $timestamp = time();//时间戳
        $nonce = rand_code();//随机串
        $header = $this->sign($timestamp,$nonce,$http_method,'https://api.mch.weixin.qq.com/v3/certificates','');

        $a = $this->curl($http_method,'https://api.mch.weixin.qq.com/v3/certificates','',$header,$timeout=5);
        dump($a);
        die;
    }
    ///JSAPI调起支付，构建签名 paySign 字段
    private function paySign($appid,$timestamp,$nonce,$package){
        //构造签名串
        $message = $appid."\n".
            $timestamp."\n".
            $nonce."\n".
            $package."\n";//报文主体
        $mch_private_key = openssl_get_privatekey(file_get_contents(config('wx')['api_key']));
        openssl_sign($message, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');
        $paySign= base64_encode($raw_sign);
        return $paySign;
    }
    /**
     * $out_trade_no string[6,32] 订单号
     * $money any-number 金额
     * $timestamp string 时间戳
     * $notify_url string 退款成功回调
    **/
    //发起退款
    public  function foundMoney($out_trade_no,$money,string $timestamp,$notify_url=''){

        $body = [
            'out_trade_no'=>$out_trade_no,
            'out_refund_no'=> md5($out_trade_no),
            'notify_url'=>empty($notify_url)?$_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['HTTP_HOST'].'/wx_pay/js_api_pay_v3/refound_callback':$notify_url,
            'amount'=>[
                'refund'=>intval( strval($money * 100) ),
                'total'=>intval( strval($money * 100) ),
                'currency'=>'CNY'
            ]
        ];
        $body_json = stripslashes(json_encode($body));
        $nonce = rand_code();//随机串
        $http_method = 'POST';
        $found_url = 'https://api.mch.weixin.qq.com/v3/refund/domestic/refunds';
        $header = $this->sign($timestamp,$nonce,$http_method,$found_url,$body_json);
        $data = $this->curl($http_method,$found_url,$body_json,$header,$timeout=5);
        return $data;
    }
    //退款回调
    public function refound_callback(){
        //接收微信返回的参数
        $data = file_get_contents("php://input");
        //转为数组
        $notify_data =  json_decode($data,true);
        //截取 resource 数组值
        $resource =  $notify_data['resource'];
        $apiv3 = config('wx')['app_key3'];
        //解密AES///
        $AesUtil = new AesUtil($apiv3);

        $associatedData = $resource['associated_data'];
        $nonceStr = $resource['nonce'];
        $ciphertext = $resource['ciphertext'] ;
        $status = $AesUtil->decryptToString($associatedData, $nonceStr, $ciphertext);
        //file_put_contents('/www/wwwroot/blqqun.yyuebd.com/app/api/controller/2.txt',$status);

        if($status!=false){
            $ok_aes =json_decode($AesUtil->decryptToString($associatedData, $nonceStr, $ciphertext),true);
        }else{
            return json(['status'=>500,'msg'=>'解密失败']);
            exit;
        }
        //取得订单号
        $out_trade_no = $ok_aes['out_trade_no'];
        //file_put_contents('/www/wwwroot/blqqun.yyuebd.com/app/api/controller/2.txt',$out_trade_no);
        $ok_update =  Db::table('sign_order')->where('out_trade_no',$out_trade_no)->update(['refound_status'=>1,'refound_text'=>'退款成功']);
        if($ok_update){
            return json_encode(['code'=>'SUCCESS']);
        }else{
            return json_encode(['code'=>'FAIL']);
        }
    }
    //预支付签名，请求放在头部
    private function sign($timestamp,$nonce,$http_method = 'POST',$url = '',$body = '')
    {
        $mch_private_key = openssl_get_privatekey(file_get_contents(config('wx')['api_key']));
        //$timestamp = time();//时间戳
        //$nonce = rand_code();//随机串
        $url_parts = parse_url($url);
        $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
        //构造签名串
        $message = $http_method."\n".
            $canonical_url."\n".
            $timestamp."\n".
            $nonce."\n".
            $body."\n";//报文主体
        //计算签名值
        openssl_sign($message, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');
        $sign = base64_encode($raw_sign);
        //设置HTTP头
        $token = sprintf('WECHATPAY2-SHA256-RSA2048 mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
            config('wx')['mch_id'], $nonce, $timestamp, config('wx')['serial_no'], $sign);
        $headers = [
            "Accept: application/json",
            "User-Agent: */*",
            "Content-Type: application/json; charset=utf-8",
            "Authorization: {$token}",
        ];
        return $headers;
    }
    //发起post请求
    private function curl($http_method,$url,$param_data,$header,$timeout=5){
        $ch = curl_init();
        // 设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        if($http_method=='POST'){
            // post数据
            curl_setopt($ch, CURLOPT_POST, 1);
            // post的变量
            curl_setopt($ch, CURLOPT_POSTFIELDS, $param_data);
        }
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        //查看头部
        //curl_setopt($ch, CURLINFO_HEADER_OUT, true);
        // 运行curl，结果以jason形式返回
        $res = curl_exec($ch);
        //$header即返回请求的header头
        // $header = curl_getinfo($ch, CURLINFO_HEADER_OUT);
        //关闭链接
        curl_close($ch);
        // 取出数据
        return json_decode($res, true);
    }

}